package com.baihejia.common.dubbo.server;

import com.baihejia.common.dubbo.domain.AvgPrice;
import com.baihejia.common.dubbo.domain.BuildTime;
import com.baihejia.common.dubbo.domain.Community;
import com.baihejia.common.dubbo.domain.CommunityQuery;
import com.baihejia.common.dubbo.domain.GeoPoint;
import com.baihejia.common.dubbo.domain.SortField;

import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.geo.GeoDistance;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.MatchPhraseQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;


public class CommunityClient extends Es<Community, CommunityQuery> {

    public CommunityClient() {
        super("community-index", "community");
    }

	@Override
	protected XContentBuilder buildMapping() throws Exception {
		return XContentFactory.jsonBuilder().prettyPrint()
	        .startObject()
	        .startObject("community")
	        .startObject("properties")
	        .startObject("avgPrice")
	        .field("type", "double")
	        .endObject()
	        .startObject("coordinates")
	        .field("type", "geo_point")
	        .endObject()
	        .startObject("keywords")
	        .field("type", "text")
	        .field("analyzer", "ik_max_word")
	        .endObject()
	        .startObject("cityId")
	        .field("type", "long")
	        .endObject()
	        .startObject("areaId")
	        .field("type", "long")
	        .endObject()
	        .startObject("businessAreaId")
	        .field("type", "long")
	        .endObject()
	        .startObject("dsCityId")
	        .field("type", "long")
	        .endObject()
	        .startObject("dsAreaId")
	        .field("type", "long")
	        .endObject()
	        .startObject("dsBusinessAreaId")
	        .field("type", "long")
	        .endObject()
	        .startObject("builtDate")
	        .field("type", "integer")
	        .endObject()
	        .startObject("buildingType")
	        .field("type", "text")
	        .field("analyzer", "ik_max_word")
	        .endObject()
	        .startObject("name")
	        .field("type", "text")
	        .endObject()
	        .startObject("recentVppv")
	        .field("type", "long")
	        .endObject()
	        .startObject("vppvTime")
	        .field("type", "long")
	        .endObject()
	        .startObject("onlineWeight")
	        .field("type", "integer")
	        .endObject()
	        .startObject("avgPrice")
	        .field("type", "double")
	        .endObject()
	        .startObject("id")
	        .field("type", "long")
	        .endObject()
	        .startObject("hasAvgPrice")
	        .field("type", "integer")
	        .endObject()
	        .startObject("hasListImage")
	        .field("type", "integer")
	        .endObject()
	        .startObject("state")
	        .field("type", "integer")
	        .endObject()
	
	        .endObject()
	        .endObject()
	        .endObject();
	}

	@Override
	protected void rebuildIndex(String index) {
		
	}

	@Override
	protected void putExtraFields(Map<String, Object> jsonObject,
			Community entity) {
		
	}

	@Override
	protected SearchHits esHits(CommunityQuery query) throws Exception {
		BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
		if (StringUtils.isNotBlank(query.keywords)) {
            MatchPhraseQueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("keywords", query.keywords);
            boolQueryBuilder.must(queryBuilder);
        }
		
		if(StringUtils.isNotBlank(query.name)){
			MatchPhraseQueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("name", query.name);
            boolQueryBuilder.must(queryBuilder);
		}
		
		List<GeoPoint> points = query.geoPoints;
        if (points != null && points.size() > 0) {
            double startDistance = 0d;
            double endDistance = 1.2;
            if (query.startDistance >0 && query.endDistance >0) {
                startDistance = query.startDistance;
                endDistance = query.endDistance;
            }
            BoolQueryBuilder mustGeoBoolQueryBuilder = QueryBuilders.boolQuery();
            for (GeoPoint point : points) {
                GeoDistanceQueryBuilder geoDistanceQueryBuilder = QueryBuilders.geoDistanceQuery("coordinates")
                        .point(new org.elasticsearch.common.geo.GeoPoint(point.lat, point.lon))
                        .distance(endDistance, DISTANCE_UNIT)
                        .geoDistance(GeoDistance.ARC);
                mustGeoBoolQueryBuilder.should(geoDistanceQueryBuilder);
            }

            boolQueryBuilder.must(mustGeoBoolQueryBuilder);

            if (startDistance > 0) {
                BoolQueryBuilder mustNotGeoBoolQueryBuilder = QueryBuilders.boolQuery();
                for (GeoPoint point : points) {
                    GeoDistanceQueryBuilder geoDistanceQueryBuilder = QueryBuilders.geoDistanceQuery("coordinates")
                            .point(new org.elasticsearch.common.geo.GeoPoint(point.lat, point.lon))
                            .distance(startDistance, DISTANCE_UNIT)
                            .geoDistance(GeoDistance.ARC);
                    mustNotGeoBoolQueryBuilder.should(geoDistanceQueryBuilder);
                }
                boolQueryBuilder.mustNot(mustNotGeoBoolQueryBuilder);
            }
        }

		if(query.businessAreaId>0){
			TermQueryBuilder queryBuilder = QueryBuilders.termQuery("dsBusinessAreaId", query.businessAreaId);
            boolQueryBuilder.must(queryBuilder);
		} else if (query.areaId>0) {
            TermQueryBuilder queryBuilder = QueryBuilders.termQuery("dsAreaId", query.areaId);
            boolQueryBuilder.must(queryBuilder);
        } else if (query.cityId >0) {
            TermQueryBuilder queryBuilder = QueryBuilders.termQuery("dsCityId", query.cityId);
            boolQueryBuilder.must(queryBuilder);
        }

		if (query.buildTimeList != null) {
			BoolQueryBuilder boolBuildTimeQuery = QueryBuilders.boolQuery();
            for (BuildTime buildTime : query.buildTimeList) {
            	RangeQueryBuilder queryBuilder =  QueryBuilders.rangeQuery("builtDate");
            	queryBuilder.from(buildTime.startTime,true).to(buildTime.endTime,true);
            	boolBuildTimeQuery.should(queryBuilder);
			}
            boolQueryBuilder.must(boolBuildTimeQuery);
        }

		if (query.avgPriceList != null) {
			BoolQueryBuilder boolAvgPriceQuery = QueryBuilders.boolQuery();
            for (AvgPrice avgPrice : query.avgPriceList) {
            	RangeQueryBuilder queryBuilder =  QueryBuilders.rangeQuery("avgPrice");
            	queryBuilder.from(avgPrice.startPrice,true).to(avgPrice.endPrice,true);
            	boolAvgPriceQuery.should(queryBuilder);
			}
            boolQueryBuilder.must(boolAvgPriceQuery);
        }

		if (query.typeList != null) {
			BoolQueryBuilder boolTypeQuery = QueryBuilders.boolQuery();
			for (String type : query.typeList) {
				MatchPhraseQueryBuilder queryBuilder = QueryBuilders.matchPhraseQuery("buildingType", type);
				boolTypeQuery.should(queryBuilder);
			}
			boolQueryBuilder.must(boolTypeQuery);
		}
		if(query.state>0){
			 TermQueryBuilder queryBuilder = QueryBuilders.termQuery("state", query.state);
	         boolQueryBuilder.must(queryBuilder);
		}
		if (query.start < 0) {
			query.start = 0;
        }

		if (query.limit <= 0 || query.limit > 1000) {
			query.limit = 1000;
        }

		if (query.start + query.limit > SEARCH_LIMIT) {
			query.limit = SEARCH_LIMIT - query.start;
        }
		
		GeoPoint geoPoint = query.geoPoint;
		if(geoPoint!=null){
			TermQueryBuilder communityBuilder = QueryBuilders.termQuery("id", query.id);
			boolQueryBuilder.mustNot(communityBuilder);
		}
		SearchRequestBuilder searchRequestBuilder = client.prepareSearch(getIndexAlias()).setTypes(getType())
                .setQuery(boolQueryBuilder)
                .setFrom(query.start)
                .setSize(query.limit);

		SortField sortField = query.sortField;
		
		//附近小区
		if(geoPoint!=null){
			searchRequestBuilder.addSort(SortBuilders.geoDistanceSort("coordinates", new org.elasticsearch.common.geo.GeoPoint(geoPoint.lat,geoPoint.lon)));
		}
        if (sortField != null) {
            searchRequestBuilder.addSort(SortBuilders.fieldSort(sortField.name()).order(SortOrder.valueOf(query.sortOrder.name())));
        }
        if (!StringUtils.isNotBlank(query.keywords)) {
        	searchRequestBuilder
        			.addSort(SortBuilders.fieldSort("hasListImage")
        			.order(SortOrder.DESC)).addSort(SortBuilders.fieldSort("hasAvgPrice").order(SortOrder.DESC));
        }
        searchRequestBuilder
                .addSort(SortBuilders.fieldSort("onlineWeight").order(SortOrder.DESC))
                .addSort(SortBuilders.fieldSort("vppvTime").order(SortOrder.DESC))
                .addSort(SortBuilders.fieldSort("recentVppv").order(SortOrder.DESC));
		
        SearchResponse resp = searchRequestBuilder.execute().actionGet();
        SearchHits searchHits = resp.getHits();
		return searchHits;
	}
    
//	public static boolean createIndex() throws Exception {
//        client.admin().indices().prepareCreate(INDEX).execute().actionGet();
//        XContentBuilder contentBuilder = buildMapping();
//        PutMappingResponse response = client
//                .admin()
//                .indices()
//                .preparePutMapping(INDEX)
//                .setType(TYPE)
//                .setSource(contentBuilder)
//                .execute()
//                .actionGet();
//        return response.isAcknowledged();
//    }
//	
//	public static void buildCommunity(Community community) throws Exception {
//        client.prepareIndex(INDEX, TYPE, String.valueOf(community.id))
//        .setSource(JsonUtils.toJson(community), XContentType.JSON)
//        .execute()
//        .actionGet();
//    }
//
//    public static void buildCommunities(List<Community> communities) throws Exception {
//        BulkRequestBuilder prepareBulk = client.prepareBulk();
//        for (Community community : communities) {
//            prepareBulk.add(client.prepareIndex(INDEX, TYPE, String.valueOf(community.id)).setSource(JsonUtils.toJson(community), XContentType.JSON));
//        }
//        prepareBulk.execute().actionGet();
//    }
//   
//    public static void updateBulk(List<String> ids, Map<String, Object> data) throws Exception{
//    	BulkRequestBuilder prepareBulk = client.prepareBulk();
//    	for (String id : ids) {
//    		prepareBulk.add(client.prepareUpdate(INDEX, TYPE, id).setDoc(JsonUtils.toJson(data), XContentType.JSON));
//		}
//    	prepareBulk.execute().actionGet();
//    }
//    
//    public static Community getById(Long id) {
//        SearchRequestBuilder searchRequestBuilder = client.prepareSearch(INDEX).setTypes(TYPE).setQuery(QueryBuilders.idsQuery().addIds(String.valueOf(id)));
//        SearchResponse resp = searchRequestBuilder.execute().actionGet();
//        String string = resp.getHits().getHits()[0].getSourceAsString();
//        return JsonHelper.fromString(string, Community.class);
//    }

}
